package com.lanyou.esb.cook.proxy.auth.impl;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

import com.lanyou.esb.cook.proxy.auth.AuthInvocation;
import com.lanyou.esb.cook.proxy.auth.processor.AcquireAuthProcessor;
import com.lanyou.esb.cook.proxy.auth.processor.VerifyAuthProcessor;
import com.lanyou.esb.cook.proxy.common.Constants;
import com.lanyou.esb.cook.proxy.common.SystemResCode;
import com.lanyou.esb.cook.proxy.common.ParamFactory;
import com.lanyou.esb.cook.proxy.entity.FieldSystem;
import com.lanyou.esb.cook.proxy.entity.Http;
import com.lanyou.esb.cook.proxy.entity.Token;
import com.lanyou.esb.cook.proxy.exception.AuthException;
import com.lanyou.esb.cook.proxy.meta.AuthType;
import com.lanyou.esb.cook.proxy.meta.Environment;
import com.lanyou.esb.cook.proxy.meta.IfType;
import com.lanyou.esb.cook.proxy.service.impl.TraceLogServiceImpl;

/**
 * 验证调度器
 * 
 * @author Davey.wu
 */
public class AuthInvocationImpl implements AuthInvocation {

	/** 获取校验信息处理接口集合 **/
	private static Map<IfType, Map<AuthType, AcquireAuthProcessor>> ACUQIRE_AUTH_PROCESSORS = new HashMap<>();
	/** 验证权限处理接口集合 **/
	private static Map<AuthType, VerifyAuthProcessor> VERIFY_AUTH_PROCESSORS = new HashMap<>();

	@Override
	public Map<String, Object> getAuthInfo(HttpServletRequest request,
			String content, Http http, Environment environment)
			throws AuthException, Exception {

		if (TraceLogServiceImpl.isTrace()) {
			// 记录跟踪日志
			TraceLogServiceImpl.addTraceLog(Constants.MSG_ACQUIRE_AUTH_INFO);
		}
		// 获取接口类型
		IfType ifType = IfType.get(http.getType());

		AuthType authType = AuthType.get(http.getAuthType());
		AcquireAuthProcessor acquireAuthProcessor = getAcquireAuthProcessor(
				ifType, authType);
		if (acquireAuthProcessor == null) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_AUTH_TYPE_NOT_SUPPORT,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.MSG_IF_TYPE, Constants.FLAG_EQUAL,
						(ifType != null ? ifType.ValueCode : ""),
						Constants.FLAG_COMMA_SYMBOL, Constants.MSG_AUTH_TYPE
								+ Constants.FLAG_EQUAL,
						(authType != null ? authType.ValueCode : ""),
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_AUTH_TYPE_NOT_SUPPORT,
					SystemResCode.CODE_AUTH_TYPE_NOT_SUPPORT);
		}
		Map<String, Boolean> parameters = ParamFactory.getParameters(authType);
		// 获取授权信息
		Map<String, Object> authInfo = acquireAuthProcessor.acquire(request,
				content, parameters);
		authInfo.put(Constants.INTERFACE_CODE, http.getCode());
		authInfo.put(Constants.ENVIRONMENT, environment);
		return authInfo;
	}

	@Override
	public boolean auth(String address, FieldSystem system, Http http,
			String callSystemCode, Environment environment,
			Map<String, Object> authInfo, Token token) throws AuthException,
			Exception {
		if (Environment.PRODUCTION == environment) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(Constants.MSG_BEGIN_AUTH);
			}
		}
		if (Environment.PRODUCTION == environment) {
			// 白名单校验
			authWhiteList(address, system.getCode(), callSystemCode, http,
					token);
		}
		VerifyAuthProcessor verifyAuthProcessor = getVerifyAuthProcessor(AuthType
				.get(http.getAuthType()));
		if (verifyAuthProcessor == null) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl
						.addTraceLog(SystemResCode.MSG_AUTH_TYPE_NOT_SUPPORT,
								Constants.FLAG_LEFT_SQUARE_BRACKET,
								Constants.MSG_AUTH_TYPE, Constants.FLAG_EQUAL,
								http.getAuthType(),
								Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_AUTH_TYPE_NOT_SUPPORT,
					SystemResCode.CODE_AUTH_TYPE_NOT_SUPPORT);
		}
		// 校验认证信息
		return verifyAuthProcessor.verify(system, http, authInfo, token);
	}

	@Override
	public void bindAcquireAuthProcessor(AcquireAuthProcessor processor) {
		if (processor == null) {
			return;
		}
		Map<AuthType, AcquireAuthProcessor> map = ACUQIRE_AUTH_PROCESSORS
				.get(processor.getIfType());
		if (map == null) {
			map = new HashMap<>();
			ACUQIRE_AUTH_PROCESSORS.put(processor.getIfType(), map);
		}
		// 将获取校验信息服务加入窗口
		map.put(processor.getAuthType(), processor);
	}

	@Override
	public void unbindAcquireAuthProcessor(AcquireAuthProcessor processor) {
		if (processor == null) {
			return;
		}
		Map<AuthType, AcquireAuthProcessor> map = ACUQIRE_AUTH_PROCESSORS
				.get(processor.getIfType());
		if (map == null) {
			return;
		}
		// 将获取校验信息服务从容器中移除
		map.remove(processor.getAuthType());
	}

	@Override
	public void bindVerifyAuthProcessor(VerifyAuthProcessor processor) {
		if (processor == null) {
			return;
		}
		// 验证权限服务加入容器
		VERIFY_AUTH_PROCESSORS.put(processor.getAuthType(), processor);
	}

	@Override
	public void unbindVerifyAuthProcessor(VerifyAuthProcessor processor) {
		if (processor == null) {
			return;
		}
		// 将验证权限服务从容器中移除
		ACUQIRE_AUTH_PROCESSORS.remove(processor.getAuthType());
	}

	/**
	 * 白名单校验
	 * 
	 * @param address
	 *            ：请求原地址
	 * @param systemCode
	 *            ：目标系统编码
	 * @param callSystemCode
	 *            ：调用方系统编码
	 * @param http
	 *            ：目标接口
	 * @throws Exception
	 */
	private void authWhiteList(String address, String systemCode,
			String callSystemCode, Http http, Token token) throws Exception {
		if (TraceLogServiceImpl.isTrace()) {
			// 记录跟踪日志
			TraceLogServiceImpl
					.addTraceLog(Constants.MSG_BEGIN_CHECK_WHITE_LIST);
		}

		String whiteList = token != null ? (token.getIpWhiteList()) : "";
		// 如果存在白名单，并且启用，则判断白名单
		if (StringUtils.isNoneBlank(whiteList)
				&& whiteList.indexOf(address) < 0) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_NOT_ACCESABLE_IP,
						Constants.FLAG_LEFT_SQUARE_BRACKET, Constants.IP,
						Constants.FLAG_EQUAL, address,
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}

			throw new AuthException(SystemResCode.MSG_NOT_ACCESABLE_IP,
					SystemResCode.CODE_NOT_ACCESABLE_IP);
		}
	}

	/**
	 * 根据验证类型获取相应的验证信息获取器
	 * 
	 * @param type
	 *            ：验证类型
	 * @return
	 */
	private VerifyAuthProcessor getVerifyAuthProcessor(AuthType type) {
		if (VERIFY_AUTH_PROCESSORS == null) {
			return null;
		}
		return VERIFY_AUTH_PROCESSORS.get(type);
	}

	/**
	 * 根据验证类型获取相应的验证处理器
	 * 
	 * @param ifType
	 *            ：接口类型
	 * @param authType
	 *            ：校验类型
	 * @return
	 */
	private AcquireAuthProcessor getAcquireAuthProcessor(IfType ifType,
			AuthType authType) {
		if (ACUQIRE_AUTH_PROCESSORS == null) {
			return null;
		}
		Map<AuthType, AcquireAuthProcessor> map = ACUQIRE_AUTH_PROCESSORS
				.get(ifType);
		if (map == null) {
			return null;
		}
		return map.get(authType);
	}

}
